package com.zhss.demo.register.server;

import java.util.Map;

/**
 * 微服务存活状态监控组建
 * @author gubatian
 * @date 2021/9/7 6:06 下午
 */
public class ServiceAliveMonitor {

    /**
     * 检查服务实力是否存活的间隔
     */
    private final static Long CHECK_ALIVE_INTERVAL = 60 * 1000L;
    private Daemon daemon = new Daemon();
    public ServiceAliveMonitor() {
        // 只要设置了这个标志位，就代表这个线程是一个daemon线程，后台线程
        // 非daemon线程，我们一般叫做工作线程
        // 如果工作线程（main线程）都结束了，daemon线程是不会阻止jvm进程退出的
        // daemon线程会跟着jvm进程一起退出
        daemon.setDaemon(true);
        daemon.setName("ServiceAliveMonitor");
    }
    /**
     * 启动后台线程
     */
    public void start() {
        daemon.start();
    }
    /**
     * 负责监控微服务存活状态的后台线程
     */
    private class Daemon extends Thread {
        private ServiceRegistry serviceRegistry = ServiceRegistry.getInstance();
        @Override
        public void run() {
            Map<String, Map<String, ServiceInstance>> registryMap;
            while (true) {
                try {
                    SelfProtectionPolicy selfProtectionPolicy = SelfProtectionPolicy.getInstance();
                    if (selfProtectionPolicy.isEnable()) {
                        // 开启自我保护机制
                        Thread.sleep(CHECK_ALIVE_INTERVAL);
                        continue;
                    }
                    registryMap =  serviceRegistry.getRegistry();
                    Map<String, ServiceInstance> serviceInstanceMap;
                    for (String serviceName : registryMap.keySet()) {
                        serviceInstanceMap = registryMap.get(serviceName);
                        for (ServiceInstance serviceInstance : serviceInstanceMap.values()) {
                            // 说明服务实例距离上一次发送心跳已经超过90秒了
                            // 认为这个服务实例已经死了
                            // 从注册表中摘除这个服务实例
                            if (!serviceInstance.isAlive()) {
                                serviceRegistry.remove(serviceName, serviceInstance.getServiceInstanceId());
                                // 更新自我保护阈值
                                synchronized (SelfProtectionPolicy.class) {
                                    selfProtectionPolicy.setExpectedHeartbeatRate
                                            (selfProtectionPolicy.getExpectedHeartbeatRate() -2);
                                    selfProtectionPolicy.setExpectedHeartbeatThreshold(
                                            (long) (selfProtectionPolicy.getExpectedHeartbeatRate()
                                                    * SelfProtectionPolicy.HEARTBEAT_RATE_THRESHOLD));
                                }
                            }
                        }
                    }
                    Thread.sleep(CHECK_ALIVE_INTERVAL);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
